﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace TableTop.DataManagement.Addon
{
    public class AddonManager
        : IDisposable
    {
        private bool bDisposed = false;

        private object LockObject = null;
        
        private Dictionary<Guid, Addon> AddonsDictionary
        {
            get;
            set;
        }

        public event EventHandler<AddonUpdateEventArgs> Updating = null;

        public AddonInfo[] Addons
        {
            get
            {
                List<AddonInfo> lstAddons = null;

                lstAddons = new List<AddonInfo>();

                lock (this.LockObject)
                {
                    foreach (Addon ca in this.AddonsDictionary.Values)
                    {
                        AddonInfo aiInfo = null;

                        aiInfo = ca.Information;
                        lstAddons.Add(aiInfo);
                    }
                }

                return lstAddons.ToArray();
            }
        }

        public Addon this[Guid Key]
        {
            get
            {
                if (this.AddonsDictionary.ContainsKey(Key))
                    return this.AddonsDictionary[Key];
                else
                    return null;
            }
        }

        public String AddonsPath
        {
            get;
            private set;
        }
        
        public AddonManager()
            : this("Addons")
        {
        }

        public AddonManager(String AddonPath)
        {
            this.AddonsPath = AddonPath;
            this.LockObject = new object();
            this.AddonsDictionary = new Dictionary<Guid, Addon>();
        }

        public void Update()
        {
            DirectoryInfo diInfo = null;
            FileInfo[] fiFiles = null;
            AddonUpdateEventArgs e = null;
            int iChecked = 0;
            int iToCheck = 0;

            if (this.AddonsDictionary.Count > 0)
            {
                // foreach (AddonHelper ad in this.AddonsDictionary.Values)
                //    ad.Dispose();
            }

            this.AddonsDictionary.Clear();
                        
            diInfo = new DirectoryInfo(this.AddonsPath);

            if (diInfo.Exists == true)
            {
                fiFiles = diInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
                iChecked = 0;
                if (fiFiles != null)
                    iToCheck = fiFiles.Length;
                else
                    iToCheck = 0;

                if (this.Updating != null)
                {
                    e = new AddonUpdateEventArgs(AddonUpdateActions.StartUpdating, 0, iToCheck);
                    this.Updating.BeginInvoke(this, 
                                              e, 
                                              new AsyncCallback(this.UpdatingAsyncCallback), 
                                              null);
                }
                
                foreach (FileInfo fi in fiFiles)
                {
                    bool bIsAddon = false;
                    Addon aCurrentAddon = null;

                    bIsAddon = AddonHelper.IsAddonAssembly(fi.FullName);
                    iChecked++;                    

                    if (bIsAddon == true)
                    {
                        aCurrentAddon = new Addon(fi.FullName);
                        this.AddonsDictionary.Add(aCurrentAddon.ID, aCurrentAddon);

                        if (this.Updating != null)
                        {
                            e = new AddonUpdateEventArgs(AddonUpdateActions.AddonFound, iChecked, iToCheck);
                            this.Updating.BeginInvoke(this,
                                                      e,
                                                      new AsyncCallback(this.UpdatingAsyncCallback),
                                                      null);
                        }

                        // Merges resources.
                        System.Windows.Application.Current.Resources.MergedDictionaries.Add(aCurrentAddon.EntryPoint.Resources);
                    }
                    else
                    {
                        if (this.Updating != null)
                        {
                            e = new AddonUpdateEventArgs(AddonUpdateActions.FileSkipped, iChecked, iToCheck);
                            this.Updating.BeginInvoke(this,
                                                      e,
                                                      new AsyncCallback(this.UpdatingAsyncCallback),
                                                      null);
                        }
                    }                    
                }
            }

            if (this.Updating != null)
            {
                e = new AddonUpdateEventArgs(AddonUpdateActions.UpdateEnded, iChecked, iToCheck);
                this.Updating.BeginInvoke(this,
                                          e,
                                          new AsyncCallback(this.UpdatingAsyncCallback),
                                          null);
            }
        }

        private void UpdatingAsyncCallback(IAsyncResult ar)
        {
            this.Updating.EndInvoke(ar);
        }

        public void Dispose()
        {
            if (this.bDisposed == false)
            {

                lock (this.LockObject)
                {
                    //foreach (AddonHelper ad in this.AddonsDictionary.Values)
                    //    ad.Dispose();
                }

                this.AddonsDictionary.Clear();
                this.AddonsDictionary = null;
                this.bDisposed = true;
            }
            else
                throw new ObjectDisposedException(String.Empty, "Object already disposed");
        }
    }
}
